#include "stdafx.h"
#include "worldproxy.h"
#include "../scene.h"
#include "../isceneobjectvisitor.h"
#include "../potion.h"
#include "../spell.h"
#include "../mage.h"

namespace {
class VisibleObjectsAggregator : public ISceneObjectVisitor
{
public:
    VisibleObjectsAggregator(const vec2f &selfPosition,
                             UnitsArray *units,
                             SpellsArray *spells,
                             BonusesArray *bonuses) :
        _selfPosition(selfPosition),
        _units(units),
        _spells(spells),
        _bonuses(bonuses)
    {
        assert(units);
        assert(spells);
        assert(bonuses);
    }

    ~VisibleObjectsAggregator()
    {
    }

    void visit(Mage *mage)
    {
        assert(mage);
        if (isVisible(mage))
            _units->add(mage);
    }

    void visit(Potion *potion)
    {
        assert(potion);
        if (isVisible(potion))
            _bonuses->add(potion);
    }

    void visit(Spell *spell)
    {
        assert(spell);
        if (isVisible(spell))
            _spells->add(spell);
    }

private:
    bool isVisible(SceneObject *object)
    {
        vec2f pos(object->x(), object->y());
        float prod = dot(pos, _selfPosition);

        return (prod >= 0);
    }

    vec2f _selfPosition;
    UnitsArray *_units;
    SpellsArray *_spells;
    BonusesArray *_bonuses;
};
}

WorldProxy::WorldProxy(const Scene *scene, const Mage *mage) :
    _scene(scene),
    _mage(mage),
    _self(0)
{
}

WorldProxy::~WorldProxy()
{
}

ISelfControl *WorldProxy::getSelfControl() const
{
    return _self;
}

float WorldProxy::width() const
{
    assert(_scene);
    return _scene->width();
}

float WorldProxy::height() const
{
    assert(_scene);
    return _scene->height();
}

void WorldProxy::renewSelfControl()
{
    std::unique_ptr<UnitsArray> units(new UnitsArray());
    std::unique_ptr<SpellsArray> spells(new SpellsArray());
    std::unique_ptr<BonusesArray> bonuses(new BonusesArray());
    _self = new SelfControl(_mage, units.get(), spells.get(), bonuses.get());

    VisibleObjectsAggregator aggregator(vec2f(_mage->x(), _mage->y()),
                                        units.release(),
                                        spells.release(),
                                        bonuses.release());
    _scene->accept(&aggregator);
}
